package com.test.base.netty_upgrade.selfprotocol.protocol;

import com.test.base.netty_upgrade.selfprotocol.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * description 自定义编解码器件
 * 自定义的编码器是实现自定义protocol的基本方式
 *
 * @author zken
 * @CreateDate 2024/11/21 20:04:42
 */
@Slf4j
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> out) throws Exception {
        ByteBuf outBuf = ctx.alloc().buffer();
        // 1.写入魔数4个字节
        outBuf.writeBytes(new byte[]{1, 2, 3, 4});
        // 2.写入版本，1个字节
        outBuf.writeByte(1);
        // 3.写入序列化方式，如果是jdk则为0，如果是json则为1
        outBuf.writeByte(0);
        // 4.字节指令的类型，1个字节
        outBuf.writeByte(msg.getMessageType());
        // 5.写入sequenceId--4个字节，为了支持双工通信
        outBuf.writeInt(msg.getSequenceId());
        // 加一个没有意义的1字节，让buf的长度满足4的倍数
        outBuf.writeByte(0xff);
        // 6.获取内容的字节数组
        // 字节接受对象
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        // 对象接受对象
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] bytes = bos.toByteArray();
        // 7.写入讯息的字节数组的长度
        outBuf.writeInt(bytes.length);
        // 8.写入字节的序列化字节流
        outBuf.writeBytes(bytes);
        // 将转换完成的消息加入out中
        out.add(outBuf);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        // 根据in种放入的内容来进行解析
        int magicNumber = msg.readInt();
        int versionNumber = msg.readByte();
        int serialNumber = msg.readByte();
        int messageType = msg.readByte();
        int sequenceId = msg.readInt();
        // 读取占位符
        int placeHolder = msg.readByte();
        // 读取数据长度和数据内容
        int bytesLength = msg.readInt();
        // 根据长度读取body字节流的内容
        byte[] bytes = new byte[bytesLength];
        msg.readBytes(bytes, 0, bytesLength);
        // 转化为实例化对象
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
        Message message = (Message) ois.readObject();
        // 设置此次消息的类型
        message.setMessageType(messageType);
        log.debug("magicNumber:{},versionNumber:{},serialNumber:{},messageType:{},sequenceId:{},placeHolder:{},bytesLength:{}",
                magicNumber,
                versionNumber,
                serialNumber,
                messageType,
                sequenceId,
                placeHolder,
                bytesLength);
        log.debug("message:{}", message);
        // 将out中加入msg
        out.add(message);
    }
}
